package com.mswyt.utils.base;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

/**
 * @author mashuai
 * @ClassName: ReflexUtils
 * @Description: 反射相关工具类。以及bean处理
 */
public class MsReflexUtils {


    /**
     * 判断A类实现实现B接口
     *
     * @param sourceClass 类对象
     * @param tagClass    接口类对象
     * @return true-实现tagClass接口
     * @author mashuai
     */

    public static Boolean isUseDefaultMethod(Class<?> sourceClass, Class<?> tagClass) {
        Class<?>[] interfaces = sourceClass.getInterfaces();
        if (interfaces.length != 0) {
            for (Class<?> it : interfaces) {
                if (it.getName().equals(tagClass.getName())) {
                    return true;
                }
            }
        }
        return false;
    }


    /**
     * 给定一个注解A.class，找出指定B.class类中所有包含A注解的字段集合
     *
     * @param m 类.class
     * @param s 注解.class
     * @return
     * @author mashuai
     */

    public static <M, S extends Annotation> List<Field> getClassFieldA(Class<M> m, Class<S> s) {
        List<Field> list = new ArrayList<>();
        for (Field f : m.getDeclaredFields()) {
            f.setAccessible(true);
            S annotation = f.getAnnotation(s);
            if (annotation != null) list.add(f);
        }
        return list;
    }

    /***
     * 给定一个注解A.class，找出指定new B()对象，类中所有包含A注解的字段集合
     * @param m 对象实例
     * @param s 注解.class
     * @return
     * @author mashuai
     */

    public static <M, S extends Annotation> List<Field> getClassFieldA(M m, Class<S> s) {
        List<Field> list = new ArrayList<>();
        for (Field f : m.getClass().getDeclaredFields()) {
            f.setAccessible(true);
            S annotation = f.getAnnotation(s);
            if (annotation != null) list.add(f);
        }
        return list;
    }


    public static <M> Field getClassField(Class<?> cl, String fieldName) {
        for (Field f : cl.getDeclaredFields()) {
            f.setAccessible(true);
            if (f.getName().equals(fieldName)) {
                return f;
            }
        }
        MsAssertUtils.throwInnerException(fieldName + "属性，不存在" + cl.getName() + "类中");
        return null;
    }

    /**
     * 给定一个字段名称，获取val值
     *
     * @param t         对象实例
     * @param needField 需要获取字段名称
     * @return
     * @author mashuai
     */

    public static <T> Object getClassFieldVal(T t, String needField) throws Exception {
        return getClassFieldValM(t, needField);
    }

    public static <T, S> Object getClassFieldVal(T t, Function<T, S> needField) throws Exception {
        return getClassFieldValM(t, String.valueOf(needField.apply(t)));
    }

    private static <T> Object getClassFieldValM(T t, String needField) throws Exception {
        Field field = t.getClass().getDeclaredField(String.valueOf(needField));
        field.setAccessible(true);
        Object val = field.get(t);
        return val;
    }

    /**
     * 将值V，赋值给Class字段
     *
     * @param t        对象实例
     * @param setField 需要赋值的字段
     * @param v        值
     * @author mashuai
     */

    public static <T> void setClassFieldVal(T t, String setField, Object v) throws Exception {
        Field f = t.getClass().getDeclaredField(setField);
        f.setAccessible(true);
        f.set(t, v);
    }


    /**
     * 获取某个class类的某个具体方法对象
     *
     * @param clazz          class对象
     * @param methodName     方法名称
     * @param parameterTypes 参数类型.class
     * @return
     * @author mashuai
     */

    public static <T> Method getMethod(Class<T> clazz, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {
        Method method = clazz.getMethod(methodName, parameterTypes);
        return method;
    }

    /**
     * 调用某个class下方法。
     *
     * @param clazz  class对象
     * @param method 方法
     * @param args   参数值
     * @return
     * @author mashuai
     */

    public static <T> Object invokeMethod(Class<?> clazz, Method method, Object args) throws Exception {
        return method.invoke(MsIocUtils.getClassObj(clazz), args);
    }


}
